home *** CD-ROM | disk | FTP | other *** search
- /* (C) Copyright 1991 Andrew Plotkin. Permission is
- given to copy and use, as long as this copyright
- notice is retained. */
-
- #include <stdio.h>
- #include <sys/time.h>
- #include <X11/Xlib.h>
- #include <X11/keysym.h>
- #include "spatial.h"
-
- #define TICKLENGTH (25000)
- #define GLIDELENGTH (8)
- #define TURNLENGTH (8)
- #define PLUMLENGTH (3)
- #define FALLLENGTH (8)
- #define PI (3.141593)
-
- int stereo;
-
- int meterx, meterx2, metery, metersize, meterlev, meteroldlev,
- meter_f_b, meter_b_d; /* oldlev is level on fieldpm */
-
- unsigned char field[MAXFIELDXY][MAXFIELDXY][MAXFIELDZ];
- short fieldx, fieldy, fieldz;
- double fieldoffx, fieldoffx2, fieldoffy, fieldoffz;
- extern double offx, offy, offz;
- long score=(-1), dropticks;
-
- extern void plop_piece(), setup_cubies(), redo_board_globals();
- extern void setup_fieldpm(), clearfield(),
- back_to_disp(), setup_backpm();
- extern void startpiece(), rotate_piece(),
- updatetemp_tra(), updatepiece(), round_piece();
- extern void pauseloop();
- extern int collision();
-
- void clearfield()
- {
- int ix, iy, iz;
- for (ix=0; ix<fieldx; ix++)
- for (iy=0; iy<fieldy; iy++)
- for (iz=0; iz<fieldz; iz++)
- field[ix][iy][iz] = 0;
- }
-
- void initgame()
- {
- curpiece = -1;
- score = 0;
- dropticks = 80;
- meterlev = 0;
- clearfield();
- setup_cubies();
- setup_fieldpm();
- }
-
- void gameloop()
- {
- #define ST_STILL (0)
- #define ST_FALL (1)
- #define ST_TURN (2)
- #define ST_GLIDE (3)
- #define ST_PLUMMET (4)
- #define ST_SPACEHIT (5)
- #define ST_PAUSE (6)
-
- short status, res, aighhmode=0;
- short droptimer=0, stattick;
- Bool eventp;
- XEvent event, nextevent;
- long evmasks;
- char key;
- KeySym ksym;
- long lasttime;
- int toffx, toffy, toffz;
- int taxis; /* 1=x, 2=y, 3=z */
- int tdir;
- struct timeval tv;
- fd_set readbits;
- int gotit;
-
- status = ST_PAUSE;
- /*lasttime = current_usec();*/
-
- while (1) {
- if (curpiece==(-1)) {
- startpiece();
- if (curpiece==(-2)) break;
- setup_backpm();
- draw_score(backpm);
- draw_score(win);
- back_to_disp(0);
- droptimer = 0;
-
- do {
- eventp = XCheckWindowEvent(dpy,
- win, KeyPressMask, &event);
- }
- while (eventp);
- };
-
- XFlush(dpy);
-
- tv.tv_sec = 0;
- tv.tv_usec = TICKLENGTH;
- FD_ZERO(&readbits);
- FD_SET(ConnectionNumber(dpy), &readbits);
- (void)select(1+ConnectionNumber(dpy), &readbits, 0, 0, &tv);
-
- if (status == ST_STILL)
- evmasks = (KeyPressMask | ExposureMask |
- StructureNotifyMask);
- else
- evmasks = (ExposureMask | StructureNotifyMask);
-
- if (eventp = XCheckWindowEvent(dpy, win, evmasks, &event))
- switch (event.type) {
- case Expose:
- do {
- gotit = XCheckWindowEvent(dpy, win,
- ExposureMask, &nextevent);
- } while (gotit);
- back_to_disp(1);
- break;
- case KeyPress:
- XLookupString(&event, &key, 1, &ksym, NULL);
- switch (ksym) {
- case XK_Q:
- case XK_q:
- return;
- break;
- case XK_Escape:
- pauseloop();
- setup_fieldpm();
- redraw_cubies();
- setup_backpm();
- draw_score(backpm);
- draw_score(win);
- back_to_disp(1);
- break;
- case XK_asciitilde:
- aighhmode = (!aighhmode);
- break;
- case XK_h:
- case XK_j:
- case XK_k:
- case XK_l:
- case XK_i:
- case XK_m:
- if (status != ST_STILL) break;
- if (ksym==XK_i || ksym==XK_m) taxis=1;
- if (ksym==XK_h || ksym==XK_l) taxis=2;
- if (ksym==XK_j || ksym==XK_k) taxis=3;
- if (ksym==XK_i || ksym==XK_h || ksym==XK_k)
- tdir=1;
- else tdir=(-1);
- toffx = 0;
- toffy = 0;
- toffz = 0;
- updatetemp_tra(toffx, toffy, toffz, taxis,
- tdir);
- res = collision(1);
- while (res==1 || (res>=3 && res <=6)) {
- switch (res) {
- case 1:
- toffz--;
- break;
- case 3:
- toffy++;
- break;
- case 4:
- toffy--;
- break;
- case 5:
- toffx--;
- break;
- case 6:
- toffx++;
- break;
- }
- updatetemp_tra(toffx, toffy, toffz,
- taxis, tdir);
- res = collision(1);
- };
- if (res==0) {
- status = ST_TURN;
- stattick = 0;
- };
- break;
- case XK_p:
- if (status != ST_STILL) break;
- droptimer = dropticks+100;
- break;
- case XK_space:
- if (status != ST_STILL) break;
- status = ST_SPACEHIT;
- break;
- case XK_Left:
- case XK_Right:
- case XK_Up:
- case XK_Down:
- if (status != ST_STILL) break;
- toffx = 0;
- toffy = 0;
- if (ksym==XK_Left) toffx = -1;
- if (ksym==XK_Right) toffx = 1;
- if (ksym==XK_Up) toffy = -1;
- if (ksym==XK_Down) toffy = 1;
- updatetemp_tra(toffx, toffy, 0, 0, 0);
- if (collision(1)==0) {
- status = ST_GLIDE;
- stattick = 0;
- };
- break;
- };
- break;
- case ConfigureNotify:
- if (event.xconfigure.width != dispx || event.xconfigure.height != dispy) {
- dispx = event.xconfigure.width;
- dispy = event.xconfigure.height;
- XFreePixmap(dpy, backpm);
- XFreePixmap(dpy, fieldpm);
- backpm = XCreatePixmap(dpy, win,
- dispx, dispy, scndepth);
- fieldpm = XCreatePixmap(dpy, win,
- dispx, dispy, scndepth);
- redo_board_globals();
- setup_cubies();
- setup_fieldpm();
- redraw_cubies();
- setup_backpm();
- draw_score(backpm);
- draw_score(win);
- back_to_disp(1);
- }
- break;
- default:
- break;
- }
-
- {
- if (status==ST_PAUSE) status=ST_STILL;
- switch (status) {
- case ST_STILL:
- droptimer++;
- if (droptimer>dropticks) {
- droptimer=0;
- updatetemp_tra(0, 0, -1, 0, 0);
- if (collision(1)==0) {
- stattick=0;
- status = ST_FALL;
- }
- else {
- plop_piece();
- curpiece = -1;
- }
- }
- break;
- case ST_SPACEHIT:
- updatetemp_tra(0, 0, -1, 0, 0);
- if (aighhmode || collision(1)==0) {
- score++;
- stattick=1;
- status = ST_PLUMMET;
- offz -= 1.0/PLUMLENGTH;
- if (offz < -(fieldz+300.0)) {
- fprintf(stderr,
- "Vanishing point error\nSegmentation fault\n");
- exit(-1);
- }
- updatepiece();
- setup_backpm();
- back_to_disp(0);
- }
- else {
- plop_piece();
- curpiece = -1;
- status = ST_PAUSE;
- }
- break;
- case ST_GLIDE:
- stattick++;
- offx += (double)toffx/GLIDELENGTH;
- offy += (double)toffy/GLIDELENGTH;
- if (stattick==GLIDELENGTH) {
- round_piece();
- };
- updatepiece();
- setup_backpm();
- back_to_disp(0);
- if (stattick==GLIDELENGTH) {
- status = ST_PAUSE;
- };
- break;
- case ST_FALL:
- stattick++;
- offz -= 1.0/FALLLENGTH;
- if (stattick==FALLLENGTH) {
- round_piece();
- };
- updatepiece();
- setup_backpm();
- back_to_disp(0);
- if (stattick==FALLLENGTH) {
- status = ST_PAUSE;
- };
- break;
- case ST_PLUMMET:
- stattick++;
- offz -= 1.0/PLUMLENGTH;
- if (stattick==PLUMLENGTH) {
- round_piece();
- };
- updatepiece();
- setup_backpm();
- back_to_disp(0);
- if (stattick==PLUMLENGTH) {
- status = ST_SPACEHIT;
- };
- break;
- case ST_TURN:
- stattick++;
- rotate_piece(taxis, tdir*0.5*PI/TURNLENGTH);
- offx += (double)toffx/TURNLENGTH;
- offy += (double)toffy/TURNLENGTH;
- offz += (double)toffz/TURNLENGTH;
- if (stattick==TURNLENGTH) {
- round_piece();
- };
- updatepiece();
- setup_backpm();
- back_to_disp(0);
- if (stattick==TURNLENGTH) {
- status = ST_PAUSE;
- };
- break;
- }
- /*lasttime = current_usec();*/
- }
- }
- }
-
- void redo_board_globals() /* using dispx, dispy */
- {
- if (!stereo) {
- if (dispy-40<dispx-20)
- boardscale = (double)(dispy - 40);
- else
- boardscale = (double)(dispx - 20);
- halfboard = (int)boardscale/2;
- }
- else {
- if (dispy-40<(dispx-20)/2)
- boardscale = (double)(dispy - 40);
- else
- boardscale = (double)((dispx - 20)/2);
- halfboard = (int)boardscale/2;
- halfboard2 = (3.0+(fieldoffx+2.5)/1.5)*halfboard;
- }
- if (dispy-(int)boardscale > 60) {
- meterx = 32;
- metery = boardscale+30;
- }
- else {
- meterx = 176;
- metery = boardscale+10;
- }
- metersize = (((int)boardscale) - meterx) / fieldz;
- if (metersize<1) metersize = 1;
- if (stereo) {
- meterx2 = meterx + (halfboard2 - halfboard);
- /*meterx2 = meterx2 & (~7);*/
- }
- }
-
- long current_usec() /* returns the current
- time in microseconds */
- {
- struct timeval tv;
-
- gettimeofday(&tv, (struct timezone *)NULL);
- return tv.tv_usec + 1000000*(tv.tv_sec%100);
- }
-
- int elapsed(start, length) /* returns whether
- length microseconds have elapsed since start.
- Not reliable when length is more than 10^8 usec
- (100 seconds) */
- long start, length;
- {
- long now;
-
- now = current_usec();
- if (start <= now) {
- if (now-start > length) return 1;
- else return 0;
- }
- else { /* the current time has rolled
- over; add 10^8 to it */
- if (now+100000000-start > length) return 1;
- else return 0;
- }
- }
-